#ifndef _DLLPARSER_HPP_
#define _DLLPARSER_HPP_

#include <Windows.h>
#include <string>
#include <map>
#include <functional>
#include <iostream>

class DllParser
{
public:
	explicit DllParser(const std::string &dllPath)
	{
		Load(dllPath);
	}
	// 禁用拷贝构造和拷贝赋值
	DllParser(const DllParser &) = delete;
	DllParser &operator=(const DllParser &) = delete;
	~DllParser()
	{
		UnLoad();
	}

	// FunctionPtr 是函数指针类型
	template <typename FunctionPtr, typename... Args>
	auto
	ExecuteFunc(const std::string &funcName, Args &&...args)
	{

		auto f = GetFunction<FunctionPtr>(funcName);
		if (f == nullptr)
		{
			std::string s = "can not find this function " + funcName;
			throw std::exception(s.c_str());
		}
		return f(std::forward<Args>(args)...);
	}
	template <typename FunctionPtr>
	FunctionPtr *GetFunction(const std::string &funcName)
	{
		FARPROC addr = nullptr;
		if (m_map.find(funcName) == m_map.end())
		{
			addr = GetProcAddress(m_hMod, funcName.c_str());
			if (addr == nullptr)
			{
				std::string s = "can not find this function " + funcName;
				throw std::exception(s.c_str());
			}
			m_map[funcName] = addr;
		}
		else
		{
			addr = m_map[funcName];
		}
		return (FunctionPtr *)(addr);
	}

private:
	bool UnLoad()
	{
		if (m_hMod == nullptr)
			return true;

		auto b = FreeLibrary(m_hMod);
		if (!b)
			return false;

		m_hMod = nullptr;
		return true;
	}

	bool Load(const std::string &dllPath)
	{
		m_hMod = LoadLibrary(dllPath.c_str());
		if (nullptr == m_hMod)
		{
			std::cout << "LoadLibrary failed\n";
			return false;
		}

		return true;
	}

private:
	HMODULE m_hMod;
	std::map<std::string, FARPROC> m_map;
};

#endif //_DLLPARSER_HPP_